package com.yesun.dcm.config.spring;

import com.yesun.dcm.commons.rpc.URL;
import com.yesun.dcm.rpc.Exporter;
import com.yesun.dcm.rpc.Invoker;
import com.yesun.dcm.rpc.Protocol;
import com.yesun.dcm.rpc.ProxyFactory;
import com.yesun.dcm.commons.constant.Constant;
import com.yesun.dcm.commons.extension.ExtensionLoader;
import com.yesun.dcm.commons.util.NetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author chunmingdeng 2017/9/27 Create.
 * @version 1.0
 * @copyright (c) YESUN. All Rights Reserved.
 * @description: service实体
 */
public class ServiceConfig<T> extends AbstractInterfaceConfig {

    private static final Logger log = LoggerFactory.getLogger(ServiceConfig.class);

    //为防止服务被重复发布，通过AtomicBoolean实现变量原子级操作，防止线程同时操作产生问题
    private static AtomicBoolean exported = new AtomicBoolean(false);//初始值为0，表示尚未发布
    // 代理工厂类
    private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
    // 发布协议
    private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
    // Map(ServiceName ==> Instance)
    protected static final ConcurrentMap<String, Object> handlerMap = new ConcurrentHashMap<String, Object>();
    //服务接口
    protected Class<?> interfaceClass;
    //服务实现
    protected T ref;

    public Class<?> getInterface() {
        return interfaceClass;
    }

    public void setInterface(Class<?> interfaceClass) {
        this.interfaceClass = interfaceClass;
    }

    public T getRef() {
        return ref;
    }

    public void setRef(T ref) {
        this.ref = ref;
    }

    /**
     * 发布服务
     */
    public synchronized void export() {
        log.info("service export start...");
        RegistryConfig registryConfig = this.getRegistryConfig();
        ProtocolConfig protocolConfig = this.getProtocolConfig();
        doExport(protocolConfig, registryConfig);
    }

    private void doExport(ProtocolConfig protocolConfig, RegistryConfig registryConfig) {
        String protocolName = protocolConfig.getName();
        Integer port = protocolConfig.getPort();
        if(StringUtils.isEmpty(protocolName)) {
            protocolName = Constant.PROTOCOL_NAME;
        }

        //构建服务发布URL
        String host = NetUtil.getLocalAddress();
        URL url = new URL(protocolName, host, port, getRegParameters(registryConfig));

        //遍历注册中心，进行服务发布
        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class<T>) interfaceClass, url);
        Exporter<T> exporter = protocol.export(invoker, handlerMap);
        exported.set(true);

    }

    private Map<String, String> getRegParameters(RegistryConfig registryConfig) {
        Map<String, String> parameters = new HashMap<>();
        parameters.put(Constant.REG_PROTOCOL, registryConfig.getRegProtocol());
        parameters.put(Constant.ADDRESS, registryConfig.getAddress());
        parameters.put(Constant.CONNECT_TIMEOUT, String.valueOf(registryConfig.getConnectTimeout()));
        return parameters;
    }

    protected AtomicBoolean getExported() {
        return exported;
    }

}
